package com.tencent.wxcloudrun.service.impl;

import java.util.*;

import javax.annotation.Resource;

import org.quartz.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencent.wxcloudrun.domain.TQuartzJob;
import com.tencent.wxcloudrun.dto.QuartzJobDTO;
import com.tencent.wxcloudrun.exception.BusinessException;
import com.tencent.wxcloudrun.mapper.TQuartzJobMapper;
import com.tencent.wxcloudrun.service.TQuartzJobService;

import lombok.extern.slf4j.Slf4j;

/**
 * @author ziyin.zhao
 * @description 针对表【t_quartz_job(任务表)】的数据库操作Service实现
 * @createDate 2025-04-22 16:43:56
 */
@Slf4j
@Service
public class TQuartzJobServiceImpl extends ServiceImpl<TQuartzJobMapper, TQuartzJob> implements TQuartzJobService {

    @Resource
    private Scheduler scheduler;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addScheduleJob(List<QuartzJobDTO> quartzJobDTOList) {
        if (CollectionUtils.isEmpty(quartzJobDTOList)) {
            return;
        }
        List<TQuartzJob> quartzJobList = new ArrayList<>(quartzJobDTOList.size());
        for (QuartzJobDTO quartzJobDTO : quartzJobDTOList) {
            quartzJobList.add(quartzJobDTO.build());
        }
        boolean success = this.saveBatch(quartzJobList);
        if (success) {
            this.addSchedulers(quartzJobList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delScheduleJob(Long busiId, Integer busiType) {
        LambdaQueryWrapper<TQuartzJob> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TQuartzJob::getBusiId, busiId);
        queryWrapper.eq(TQuartzJob::getBusiType, busiType);
        queryWrapper.eq(TQuartzJob::getEnableFlag, 1);
        List<TQuartzJob> quartzJobList = this.list(queryWrapper);
        boolean success = this.remove(queryWrapper);
        if (success) {
            if (!CollectionUtils.isEmpty(quartzJobList)) {
                for (TQuartzJob quartzJob : quartzJobList) {
                    this.delScheduler(String.valueOf(quartzJob.getId()));
                }
            }
        }
    }

    @Override
    public void delScheduleJob4Acti(Long actiId) {
        LambdaQueryWrapper<TQuartzJob> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TQuartzJob::getBusiId, actiId);
        queryWrapper.eq(TQuartzJob::getEnableFlag, 1);
        List<TQuartzJob> quartzJobList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(quartzJobList)) {
            return;
        }
        boolean success = this.remove(queryWrapper);
        if (success) {
            if (!CollectionUtils.isEmpty(quartzJobList)) {
                for (TQuartzJob quartzJob : quartzJobList) {
                    this.delScheduler(String.valueOf(quartzJob.getId()));
                }
            }
        }
    }

    /**
     * method description: 创建定时任务
     *
     * @param id 任务序号
     * @param jobClassName 任务类名
     * @param cronExpression 时间表达式
     * @param parameter 任务参数
     * @author Ryan Zhao
     * @date 2023-08-22 12:08
     */
    private void addScheduler(String id, String jobClassName, String cronExpression, String parameter) {
        try {
            log.info("新增调度任务，任务号=[{}]", id);

            // 启动调度器
            scheduler.start();

            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(id)
                .usingJobData("param", parameter).build();

            // 表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
                .withMisfireHandlingInstructionFireAndProceed().inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger =
                TriggerBuilder.newTrigger().withIdentity(id).withSchedule(scheduleBuilder).startNow().build();

            // 调度任务
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            log.error("创建定时任务-创建失败: {}", e.getMessage(), e);
            throw new BusinessException("创建定时任务失败", e);
        } catch (RuntimeException e) {
            log.error("创建定时任务-执行异常: {}", e.getMessage(), e);
            throw new BusinessException("创建定时任务失败", e);
        } catch (Exception e) {
            log.error("创建定时任务-异常：{}", e.getMessage(), e);
            throw new BusinessException("创建定时任务异常");
        }
    }

    /**
     * method description: 批量创建定时任务
     *
     * @param quartzJobList 入参
     * @author Ryan Zhao
     * @date 2023-09-13 15:05
     */
    private void addSchedulers(List<TQuartzJob> quartzJobList) {
        try {
            log.info("创建调度任务，任务条数=[{}]", quartzJobList.size());
            // 启动调度器
            scheduler.start();
            Map<JobDetail, Set<CronTrigger>> jobDetailSetMap = new HashMap<>(quartzJobList.size());
            for (TQuartzJob quartzJobDo : quartzJobList) {
                // 构建job信息
                JobDetail jobDetail = JobBuilder.newJob(getClass(quartzJobDo.getJobClassName()).getClass())
                    .withIdentity(String.valueOf(quartzJobDo.getId())).usingJobData("param", quartzJobDo.getJobParam())
                    .build();
                // 表达式调度构建器(即任务执行的时间)
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJobDo.getJobCron())
                    .withMisfireHandlingInstructionFireAndProceed().inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
                // 按新的cronExpression表达式构建一个新的trigger
                CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(String.valueOf(quartzJobDo.getId()))
                    .withSchedule(scheduleBuilder).startNow().build();
                Set<CronTrigger> cronTriggers = new HashSet<>();
                cronTriggers.add(trigger);
                jobDetailSetMap.put(jobDetail, cronTriggers);
            }
            // 调度任务
            scheduler.scheduleJobs(Collections.unmodifiableMap(jobDetailSetMap), true);
            log.info("创建调度任务成功！");
        } catch (SchedulerException e) {
            log.error("创建定时任务-活动时间已过期: {}", e.getMessage(), e);
            throw new BusinessException("活动时间已过期", e);
        } catch (RuntimeException e) {
            log.error("创建定时任务-执行异常: {}", e.getMessage(), e);
            throw new BusinessException("创建定时任务失败", e);
        } catch (Exception e) {
            log.error("创建定时任务-异常：{}", e.getMessage(), e);
            throw new BusinessException("创建定时任务异常");
        }
    }

    /**
     * method description: 删除定时任务
     *
     * @param id 任务序号
     * @author Ryan Zhao
     * @date 2023-08-22 12:08
     */
    private void delScheduler(String id) {
        try {
            log.info("删除调度任务，任务号=[{}]", id);
            scheduler.pauseTrigger(TriggerKey.triggerKey(id));
            scheduler.unscheduleJob(TriggerKey.triggerKey(id));
            scheduler.deleteJob(JobKey.jobKey(id));
        } catch (Exception e) {
            log.error("删除调度任务-异常：{}", e.getMessage(), e);
            throw new BusinessException("删除定时任务失败");
        }
    }

    private static Job getClass(String classname) throws Exception {
        Class<?> class1 = Class.forName(classname);
        return (Job)class1.newInstance();
    }
}
